<template>
	<el-drawer :title="form.id ? t('common.editBtn') : t('common.addBtn')" v-model="visible" :close-on-click-modal="false" 
        :close-on-press-escape="true" :destroy-on-close="false" direction="rtl">
        <el-form ref="dataFormRef" :model="form" :rules="dataRules" label-width="90px" v-loading="loading">
			<el-form-item :label="t('route.routeId')" prop="routeId">
				<el-input v-model="form.routeId" :placeholder="t('route.inputRouteIdTip')" />
			</el-form-item>
			<el-form-item :label="t('route.name')" prop="name">
				<el-input v-model="form.name" :placeholder="t('route.inputNameTip')" />
			</el-form-item>
			<el-form-item :label="t('route.uri')" prop="uri">
                <el-input v-model="form.uri" :placeholder="t('route.inputUriTip')" />
			</el-form-item>
            <el-form-item :label="t('route.sortOrder')" prop="sortOrder">
                <el-input-number v-model="form.sortOrder" :placeholder="t('route.inputSortOrderTip')" :min="0" />
			</el-form-item>
            <el-form-item :label="t('route.predicates')" prop="predicates">
                <div v-for="(item, index) in form.predicates" class="w-full">
                    <!--当name在noKeyRouter时不需要指定key-->
                    <template v-if="noKeyRouter.includes(item.name)">
                        <el-divider class="flex items-center gap-4 pt-4">
                            <span class="mr-2">{{ item.name }}</span>
                            <el-icon @click="removePredicate(form,index)" class="hover:cursor-pointer  active:scale-95 transition-transform"><Delete /></el-icon>
                        </el-divider>    
                        <div>
                            <!--map循环-->
                            <template v-for="[key,value],tagIndex in getSafeMapEntries(item)" :key="key">
                                    <el-input :model-value="value" 
                                        class="mr-2" 
                                        v-if="isEditing(index,tagIndex,key,item)"
                                        :style="{ width: '190px' }"
                                        @update:model-value="(newVal:any)=>{updateArgsValue(tagIndex,key,newVal,item);}" 
                                        @blur="handleInputEditConfirm(item,key,tagIndex)"
                                        @keyup.enter="handleInputEditConfirm(item,key,tagIndex)"
                                        :placeholder="t('route.inputParamValueTip')"/>
                                    <el-tag 
                                        v-else
                                        class="mr-2" 
                                        :closable="true"
                                        @close="removeArgs(tagIndex,key,item)"
                                        @click="startEdit(item, key, tagIndex, index)" 
                                        >
                                        {{ value }}
                                    </el-tag>
                            </template>
                            <el-tag 
                                class="bg-white-500 border-dashed" 
                                @click="addArgsParams(item, index)">
                                <el-icon><Plus /></el-icon>
                                新建{{ item.name }}
                            </el-tag> 
                        </div>
                    </template>
                    <!--当name不在noKeyRouter时需要指定key-->
                    <template v-if="!noKeyRouter.includes(item.name)">
                        <el-divider class="flex items-center gap-4 pt-4 w-100">
                            <span>{{ item.name }}</span>
                            <el-icon @click="removePredicate(form,index)"><Close /></el-icon>
                        </el-divider>   
                        <div class="w-100">
                            <template v-for="(arg,key) in item.args">
                                <el-row>
                                    <el-col :span="5" class="mt-2">
                                        <span v-if="key=='header'">{{ t('route.headerName') }}</span>
                                        <span v-if="key=='regexp'">{{ t('route.paramValue') }}</span>
                                        <span v-if="key=='param'">{{ t('route.paramName') }}</span>
                                        <span v-if="key=='name'">{{ t('route.paramName') }}</span>
                                    </el-col>
                                    <el-col :span="18" class="mt-2">
                                        <el-input
                                            v-model="item.args[key]"
                                            :placeholder="t('route.inputParamValueTip')"
                                            class="mt-2 mr-3 w-70"
                                            >
                                        </el-input>
                                    </el-col>
                                </el-row>
                            </template>
                        </div>
                    </template>
                </div>
                <div class="btn pt-2 w-full">
                    <el-dropdown size="medium">
                        <template #dropdown>
                            <el-dropdown-menu>
                                <template v-for="item in tagArray">
                                    <el-dropdown-item :command="item.name" @click="predicatesHandleMenuClick(item)">
                                        {{ item.name }}
                                    </el-dropdown-item>
                                </template>
                            </el-dropdown-menu>
                        </template>
                        <el-button type="primary">
                            {{t('route.addPredicates')}}
                            <el-icon><ArrowDown /></el-icon>
                        </el-button>
                    </el-dropdown>
                </div>
            </el-form-item>
            <!--过滤器-->
            <el-form-item :label="t('route.filters')" prop="filters">
                <div v-for="(item, index) in form.filters" class="w-full">
                    <el-divider>
                        <div class="flex items-center">
                            <span v-if="item.name==='RequestRateLimiter'">
                                {{ item.name }}
                            </span>
                            <span v-else>
                                <el-input v-model="item.name" :placeholder="t('route.inputFiltersTip')" class="border-none"/>
                            </span>
                            <el-icon @click="removeFilters(form,index)" class="ml-2 hover:cursor-pointer  active:scale-95 transition-transform"><Close /></el-icon>
                        </div>
                    </el-divider>      
                    <!--map循环-->
                    <div v-for="[key,value],index in getSafeMapEntries(item)" :key="key" class="w-full">
                        <el-form-item :prop="key">
                            <el-input :model-value="key" @update:model-value="(newVal:string)=>{const oldKey=key;updateArgsKey(index,oldKey,newVal,item);}" :placeholder="t('route.inputParamNameTip')" class="w-2/5 mr-2" />
                            <el-input :model-value="value" @update:model-value="(newVal:any)=>{updateArgsValue(index,key,newVal,item);}" :placeholder="t('route.inputParamValueTip')" class="w-2/5 mr-2"/>
                            <el-icon @click="removeArgs(index,key,item)" class="hover:cursor-pointer active:scale-95 transition-transform"><Close /></el-icon>
                        </el-form-item>
                    </div>

                    <el-button type="default" class="mt-2" size="small" @click="addArgsParams(item,index)">
                        <el-icon><ArrowDown /></el-icon>{{t('route.addParam')}}
                    </el-button>
                </div>
                <div class="btn pt-2">
                    <el-dropdown size="medium">
                        <template #dropdown>
                            <el-dropdown-menu>
                                <template v-for="item in filterArray">
                                    <el-dropdown-item :command="item.name" @click="filterHandleMenuClick(item)">
                                        {{ item.name }}
                                    </el-dropdown-item>
                                </template>
                            </el-dropdown-menu>
                        </template>
                        <el-button type="primary">
                            {{t('route.addFilters')}}
                            <el-icon><ArrowDown /></el-icon>
                        </el-button>
                    </el-dropdown>
                </div>
            </el-form-item>
            <!--元数据-->
            <el-form-item :label="t('route.metadata')" prop="metadata">
                <el-divider v-if="medataEntries.length>0">
                    <div class="flex items-center">
                        Metadata
                        <el-icon @click="removeAllMetadata(form)" class="ml-2 hover:cursor-pointer  active:scale-95 transition-transform"><Close /></el-icon>
                    </div>
                </el-divider>      
                <el-form-item v-for="[key,value],index in medataEntries" :key="key">
                    <el-input :model-value="key" @update:model-value="(newVal:string)=>updateKey(index,newVal)" :placeholder="t('route.inputParamNameTip')" class="w-2/5 mr-2" />
                    <el-input :model-value="value" @update:model-value="(newVal:any)=>updateValue(key,newVal)" :placeholder="t('route.inputParamValueTip')" class="w-2/5 mr-2"/>
                    <el-icon @click="removeMetadata(form,key)" class="hover:cursor-pointer active:scale-95 transition-transform"><Close /></el-icon>
                </el-form-item>
                <div class="btn pt-2">
                    <el-button type="primary" @click="addMatadataParams(form)">
                            {{t('route.addMetadata')}}
                        <el-icon><ArrowDown /></el-icon>
                    </el-button>
                </div>
            </el-form-item>

			<el-form-item :label="t('route.remarks')" prop="remarks">
				<el-input type="textarea" maxlength="150" :rows="3" v-model="form.remarks" :placeholder="t('route.inputremarkTip')" />
			</el-form-item>
		</el-form>
		<template #footer>
			<span class="dialog-footer">
				<el-button @click="visible = false">{{ $t('common.cancelButtonText') }}</el-button>
				<el-button type="primary" @click="handleSumbitForm" :disabled="loading">{{ $t('common.confirmButtonText') }}</el-button>
			</span>
		</template>
	</el-drawer>
</template>

<script setup lang="ts" name="systemRouteDialog">
import { debounce } from 'lodash';
import { useI18n } from 'vue-i18n';
import { addOrUpdate, getObj, validateRouteId, validateRouteName } from '/@/api/admin/route';
import { useMessage } from '/@/hooks/message';
import { rule } from '/@/utils/validate';
//定义过滤器类型
interface FilterItemBase{
    name:string;
    args?:Map<string,any>;
}
type FilterItem<T=any>=FilterItemBase &{
    [key: string]: T extends Map<string, any> ? never : T;
}
// 定义子组件向父组件传值/事件
const emit = defineEmits(['refresh','update:modelValue']);

const { t } = useI18n();

// 定义变量内容
const dataFormRef = ref();
const visible = ref(false);
const loading = ref(false);


const currentNameIndex=ref(0);
const currentTagIndex=ref(-1);
const currentKey=ref('');
const tagArray=ref([
    {name:'Path',args:{}},
    {name:'Header',
    args:{
        header:'',
        regexp:'',
    }},
    {name:'Query',
    args:{
        param:'',
        regexp:''
    }},
    {name:'Method',args:{}},
    {name:'Host',args:{}},
    {name:'Cookie',args:{
        name: '',
        regexp: '',
    }},
    {name:'Param',args:{
        param:'',
        name:''
    }},
    {name:'After',args:{}},
    {name:'Before',args:{}},
    {name:'Between',args:{}},
    {name:'RemoteAddr',args:{}},

]);
//断言数组
const noKeyRouter = ['Path', 'Host', 'Method', 'After', 'Before', 'Between', 'RemoteAddr'];
//过滤器数组
const filterArray = [{ key: 0, name: '熔断器' }, { key: 1, name: '限流过滤器' }];

// 提交表单数据
const form = reactive({
    id:'',
	routeId: '',
	name: '',
	uri: '',
    predicates: [] as any[],
    filters: []as FilterItem[],
    metadata: new Map(),
	sortOrder: 0,
	remarks: '',
	delFlag: '',
	createTime: '',
	createBy: '',
	updateTime: '',
	updateBy: '',
});


// 定义校验规则
const dataRules = ref({
	routeId: [
		{ validator: rule.overLength, trigger: 'blur' },
		{ required: true, message: '路由ID不能为空', trigger: 'blur' },
		{
			validator: (rule: any, value: any, callback: any) => {
				validateRouteId(rule, value, callback, form.id !== '');
			},
			trigger: 'blur',
		},
	],
	name: [
		{ validator: rule.overLength, trigger: 'blur' },
		{ required: true, message: '路由名称不能为空', trigger: 'blur' },
		{
			validator: (rule: any, value: any, callback: any) => {
				validateRouteName(rule, value, callback, form.id !== '');
			},
			trigger: 'blur',
		},
	],
    uri: [
		{ validator: rule.overLength, trigger: 'blur' },
		{ required: true, message: '路由URI不能为空', trigger: 'blur' },
	],

	sortOrder: [
		{ validator: rule.overLength, trigger: 'blur' },
		{ required: true, message: '排序不能为空', trigger: 'blur' },
	],
});

// 打开弹窗
const openDialog = (id: string) => {
	visible.value = true;
	form.id = '';

	// 重置表单数据
	nextTick(() => {
		dataFormRef.value?.resetFields();
	});

	// 获取Post信息
	if (id) {
		form.id = id;
		getData(id);
	}
};



// 初始化表格数据
const getData = (id: string) => {
	// 获取部门数据
	getObj(id).then((res: any) => {
		Object.assign(form, res.data);
        //格式化
        formatMetadata(res);
	});
    
};

const formatMetadata=(res:any)=>{
    if(res.data.metadata&&res.data.metadata!==''&&res.data.metadata!=='{}'){
        form.metadata=new Map(Object.entries(res.data.metadata));
    }
}

//
const isEditing=(index:number,tagIndex:number,key:string,item:any)=>{
    return tagIndex===currentTagIndex.value||currentKey.value===key;
};

const startEdit=(item:any, key:string, tagIndex:number, index:number)=>{
    currentTagIndex.value=tagIndex;
    currentNameIndex.value=index;
}
//添加路由选项
const predicatesHandleMenuClick=(e:any)=>{
    form.predicates.push({
        args: e.args,
        name: e.name,
    });
}
 //删除断言
const removePredicate=(item:any,index:number)=>{
    item.predicates.splice(index,1);
}
//删除过滤器
const removeFilters=(item:any,index:number)=>{
    item.filters.splice(index,1);
}
//删除元数据
const removeMetadata=(item:any,key:string)=>{
    item.metadata.delete(key);
}
//清空所有元数据信息
const removeAllMetadata=(item:any)=>{
    item.metadata=new Map();
}
//删除元数据
const removeArgs=(index:number,key:string,item:any)=>{
    //map
    if(item.args instanceof Map){
        item.args.delete(key);
        return;
    }
    //数组
    if(Array.isArray(item.args)){
        item.args.splice(index,1);
        return;
    }
    //对象
    delete item.args[key];
    
}
//更新元数据key值
const updateArgsKey=(index:number,oldKey:string,newKey:string,item:FilterItem)=>{
    if(!item.args){
        return;
    }
    //map类型
    if(item.args instanceof Map){
        const entries=Array.from(item.args.entries());
        const [oldKey,oldValue]=entries[index];
        if(newKey&& oldKey!==newKey){
            item.args.delete(oldKey);
            item.args.set(newKey,oldValue);
        }
        return;
    }
    // 正确处理数组类型
    if (Array.isArray(item.args)) {
        const target = item.args[index] as string;
        if (target && newKey && target !== newKey) {
            (item.args as string[])[index] = newKey;
        }
        return;
    }
    //获取旧数据键值对应的value值
    const oldValue = item.args[oldKey];  
    //对象不能更新key值，只能更新value
    item.args=Object.assign({}, item.args, {
        [newKey]: oldValue,
        [oldKey]: undefined // 移除旧键
        });
    //删除旧数据    
    delete  item.args[oldKey];  
    return;
}
//更新元数据value值
const updateArgsValue=(index:number,newKey:string,newValue:any,item:any)=>{
    if (item.args instanceof Map) {
        item?.args.set(newKey,newValue);
        return;
    }
    // 正确处理数组类型
    if (Array.isArray(item.args)) {
        const target = item.args[index] as string;
        if (target && newKey && target !== newKey) {
            (item.args as string[])[index] = newKey;
        }
        return;
    }
    //对象
    if (newValue) {
        item.args[newKey] = newValue
    }
}

//防抖处理
const debounceUpdateKey=debounce((index:number,newKey:string)=>{
        updateKey(index,newKey);},1000);

//更新元数据key值
const updateKey=(index:number,newKey:string)=>{
    const entries=Array.from(form.metadata.entries());
    const [oldKey,oldValue]=entries[index];
    if(newKey&& oldKey!==newKey){
        form.metadata.delete(oldKey);
        form.metadata.set(newKey,oldValue);
    }
}
//更新元数据value值
const updateValue=(newKey:string,newValue:any)=>{
    form.metadata.set(newKey,newValue);
}
//添加args参数 
const addArgsParams=(item:any,index:number)=>{
    if (!item.args) {
        item.args = new Map();
    }
    let safeKey="";
    if (item.args instanceof Map) {
        safeKey=`_genkey_${item.args.size}`;
        item.args.set( safeKey, "");
    } else {
        // 处理普通对象情况
        safeKey = `_genkey_${Object.keys(item.args).length}`  ;
        item.args[safeKey] = "";
    }
    currentNameIndex.value=index;
    currentKey.value=safeKey;
}
//元数据处理
const medataEntries=computed(()=>Array.from(form.metadata.entries()));
//添加元数据信息
const addMatadataParams=(item:any)=>{
    if(!item.metadata){
        item.metadata=new Map;
    }
    item.metadata.set("key"+item.metadata.size+"1","");
}
//获取数组信息
const getSafeMapEntries=(map:FilterItem)=>{
    if(!map.args){
        return [];
    }
    if(map instanceof Map){
        return Array.from(map.args.entries());
    }
    return Object.entries(map.args);
}
//过滤器添加事件
const filterHandleMenuClick=(e:any)=>{
   if (e.key == 0) {
      form.filters.push({
        args: {value:''},
        name: 'Hystrix',
        title: e.name,
      });
    }
    if (e.key == 1) {
      form.filters.push({
        args:{
            'key-resolver': '#{@remoteAddrKeyResolver}',
            'redis-rate-limiter.replenishRate': 100,
            'redis-rate-limiter.burstCapacity': 100
        },
        name: 'RequestRateLimiter',
        title: e.name,
      });
    }
}

//输入框确认
const handleInputEditConfirm=(item:any,tag:any,index:number)=>{
    currentNameIndex.value=-1;
    currentTagIndex.value=-1;
    currentKey.value='';
}
//提交form表单
const handleSumbitForm=async ()=>{
  await dataFormRef.value.validate().then(() => {
      try {

        //重新构造表单提交对象,切记不可修改router对象，数组修改为字符串容易造成界面混乱
        let params = Object.assign({}, form, {
          predicates: JSON.stringify(form.predicates),
          filters: JSON.stringify(form.filters),
          metadata:JSON.stringify(Object.fromEntries(form.metadata)),
        });
        //提交表单
        addOrUpdate({ router: params }).then(() => {
        useMessage().success(t(form.id ? 'common.editSuccessText' : 'common.addSuccessText'));
          visible.value = false;
          //刷新列表
          emit('refresh');
        });
      }catch (err: any) {
		useMessage().error(err.msg);
	} finally {
        loading.value = false;
      }
    });
}
// 暴露变量
defineExpose({
	openDialog,
});
</script>
